-
-
Notifications
You must be signed in to change notification settings - Fork 730
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Place backorders for linked products via DFC integration #12856
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What a journey ! I am glad I have some background knowledge on the project 🫘
I think it looks good ! 👏
I left a few comments that should help other reviewer and some suggestion to clarify a few things.
it "completes an order", vcr: true do | ||
backorder = subject.find_or_build_order(order) | ||
|
||
expect(backorder.semanticId).to match %r{^https.*/[0-9]+$} | ||
expect(backorder.lines.count).to eq 1 | ||
|
||
subject.complete_order(order, backorder) | ||
|
||
remaining_open_order = subject.find_or_build_order(order) | ||
expect(remaining_open_order.semanticId).not_to eq backorder.semanticId | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't that be under it's own describe
block ? You are testingcomplete_order
aren't new ?
It will be addressed later on
@@ -2,13 +2,23 @@ | |||
|
|||
# Finds wholesale offers for retail products. | |||
class FdcOfferBroker | |||
Solution = Struct.new(:product, :factor, :offer) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we were on ruby >=3.2 I would have suggested to use Data
instead of Struct
here : https://ruby-doc.org/3.2.5/Data.html
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting, I didn't know about that thanks!
2877d66
to
3baa845
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well done! It was a long journey with a lot to work through, but it looks like it's near to completion now. I love how it brings together a complex standard and proves that it's possible to use in the real world.
I see three TODO
s; perhaps you're planning to work on those still.
Still, I think this looks good to me. My brain was mush for the last few commits but it mostly seems to make sense 👍 (apart from the few questions I have!)
@@ -2,13 +2,23 @@ | |||
|
|||
# Finds wholesale offers for retail products. | |||
class FdcOfferBroker | |||
Solution = Struct.new(:product, :factor, :offer) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting, I didn't know about that thanks!
app/jobs/complete_backorder_job.rb
Outdated
line.quantity = line.quantity.to_i - wholesale_items_contained_in_stock | ||
|
||
retail_stock_changes = wholesale_items_contained_in_stock * transformation.factor | ||
linked_variant.on_hand -= retail_stock_changes |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have to confess my brain didn't quite make it to the end of the PR before turning into mush.
It seems that we're adjusting the backorders relative to what they were before. Would it not be more robust to look at all current retail orders and re-calculate the backorder requirement from scratch?
Hmm.. no we can't because we don't know how much of our "on_hand" stock was from a backorder, unless we look at the backorder.
I can't work out if that's a problem or not 🤯
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, it's a tricky one. I would also favour recalculating from scratch, but the use of OFN stock is so much more helpful/flexible for this one (we've already encountered an edge case for one of our pilot hubs that will need to utilise that)...
..so long as everything always works, I think we're good! 🫣
user = order.distributor.owner | ||
|
||
# We are assuming that all variants are linked to the same wholesale | ||
# shop and its catalog: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm happy with that assumption (for now 😉 ), and it will be true for the pilots we're running.
return if open_orders.blank? | ||
|
||
# If there are multiple open orders, we don't know which one to choose. | ||
# We want the order we placed for the same distributor in the same order |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok. I'm pretty sure the Shopify Orders endpoint will display old (completed orders), we should only have 1 Draft order though.
The Shopify Hub app is storing the ID of the Order returned from the initial POST request, to utilise in future PUT requests. Could we do that ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could. And maybe we need to. I tried to get around it to have minimal local data. Local data structures increase maintenance and can become out of sync. And I was worried about longer dev times as well. But I agree that the current solution isn't great.
# | ||
# For now, we just guess: | ||
open_orders.last.tap do |order| | ||
# The DFC Connector doesn't recognise status values properly yet. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mkllnk could you elaborate on what you mean by "DFC Connector doesn't recognise status values properly"? 😟
I thought this was sorted & we haven't had any issues with the TS Connector. @lecoqlibre do we need to update the Ruby Connector?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, we can load the vocabulary with order states. The Connector doesn't have a built-in method for that but I did make it work in a separate branch. I could work on a pull request to make this part work with the importer. I was just shying away from the effort to meet the deadline. The current version is also not recognising the transformation links. That may just be the outdated context though. We are still on 1.8, I think. And I wasn't keen to follow the updates closely because you discovered bugs here and there. Happy to give it another go though.
c82527d
to
585bd88
Compare
The simplified API was only returning the response body, not allowing us to inspect if an error occurred. Since an error should be an exception when communicating with a standardised protocol, we raise an error and keep our simple API.
Apparently, the FDC implementation uses those dates to finalise orders.
The job class is getting too big.
We were already importing stock levels from offers but now we are looking at catalog items as well.
This was abandoned when the checkout was re-designed. But I want to refactor the order locking mechanism and it would be good to know that I don't break anything.
From Sidekiq's view, the job is successful when we rescue an error and it will discard it. But we want the option to inspect the job and retry it. Failing jobs are also reported to Bugsnag automatically. I didn't specify `retry: false` because that discards the job as well. But `retry: 0` should sent it straight to the dead set. No automatic retries but it's treated like a failed job.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fantastic! I have to admit I don't fully follow the web of semantics, but everything has been put together with clear and comprehensive steps, well done.
As you said, it shouldn't affect any existing functionality (from memory, any changes in the app code are very minor and should be covered by specs anyway).
So I think this is good to merge, ready to test in real life 👍
filename = File.basename(supplied_product.image) | ||
|
||
Spree::Image.new.tap do |image| | ||
PrivateAddressCheck.only_public_connections do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So glad There's A Gem For That.
@@ -240,6 +240,8 @@ def set_cost_currency | |||
end | |||
|
|||
def create_stock_items | |||
return unless stock_items.empty? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not covered directly by spec, but not a big deal.
variant.stock_items << Spree::StockItem.new( | ||
stock_location: DefaultStockLocation.find_or_create, | ||
variant:, | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if the variant model should be doing this part.
|
||
it "creates a new Spree::Product and variant" do | ||
# We need this to save stock: | ||
DefaultStockLocation.find_or_create |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm probably missing something, but it looks like this is already performed in CatalogItemBuilder. but maybe it is needed before that.
order.next # => address | ||
order.next # => delivery | ||
order.next # => payment | ||
order.next # => confirmation |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might not hurt to expect order.state to be confirmation, if perhaps the states change in the future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we should be using Orders::WorkflowService#next
to better replicate the checkout process ?
expect(order.completed?).to be true | ||
expect(order.payments.count).to eq 1 | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🏅
order.line_items.map(&:variant), | ||
) | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💯
So much to build for one seemingly small task, well done, and thanks for adding a preview.
|
||
# Combined example for performance | ||
expect(Bugsnag).to receive(:notify).and_call_original | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
😢 It's a shame we can't spec this behaviour of sidekiq's
Oops, apologies @RaggedStaff - I did not notice the staging-FR label on this PR... I'll be sure to re-stage this PR, once I'm done with testing. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had a quick look as well, looks good 👍
ℹ️ Funded Feature. Please track ALL ASSOCIATED WORK under the associated tracking code: #11678 DFC Orders
What? Why?
What should we test?
https://env-0105831.jcloud-ver-jpe.ik-server.com/api/dfc/Enterprises/test-hodmedod/SuppliedProducts
.In Shopify (https://admin.shopify.com/store/test-hodmedod):
Release notes
Changelog Category (reviewers may add a label for the release notes):
The title of the pull request will be included in the release notes.
Dependencies
Documentation updates